package rt;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import ReadWGZ.ReadFilewgzMDR;

import executor.ReflectionExecutor;
import operations.Operation;
import model.CUT;
import model.TestClusterBuilder;
import instrumentation.BlockClass;
import instrumentation.TrackerCoverage;
import ga.GAInfo;
import ga.Individual;
import util.*;
import convertTestsToJUnit.*;
public class RT {
	protected static Logger logger = Logger.getLogger("Random Generator");	
	public static GAInfo     gaInfo     = new GAInfo();

	private static TrackerCoverage tracker;
	
    private static long startTime;
    private static long elapsed;
private static  long TestTimeout = 60 * 500; /* Timeout at 30 seconds */
//private static final long TestTimeout = 60 * 1000 * 15; /* Timeout at 60 seconds */

	public static long randomseed;// = (int) GAConfig.RANDOM_SEED;
	public static float totalCoveredBranches=0;	
	static int maximumBranchNumber=Integer.MAX_VALUE;

	public static void initialize(TestClusterBuilder tCluster)throws ClassNotFoundException,IOException {
		startTime = Calendar.getInstance().getTimeInMillis();
		elapsed = Calendar.getInstance().getTimeInMillis() - startTime;
		gaInfo.setTestTimeOut(TestTimeout);
		gaInfo.setStartTime(startTime);
		gaInfo.setTestCluster(tCluster);
	}
	public static int execute() {
	      TestClusterBuilder TestCluster=gaInfo.getTestCluster();
	      int iteration;
			int noMinutes=1;
			String clzToTest=gaInfo.getClzToTest().getName();
			List<Integer> branchs = new ArrayList<Integer>( gaInfo.getClazzBranches(clzToTest));  
			maximumBranchNumber=branchs.size();
		for ( iteration = 0; (iteration <= 2000000) && (elapsed < TestTimeout) ; iteration++) {
		  List<Operation> initialConstructors= Operation.randomGenerateInitialConstructors(TestCluster);
	      List<Operation> ops=new LinkedList<Operation>(Operation.randomlyGenerateOperation(TestCluster,GAConfig.TestCaseRandomSize));

    	  Individual individual=new Individual(initialConstructors,ops);
    	  /////////////////////////////////////////////
  //  	  System.out.println("RT.execute(): "+individual.toString());
		  /////////////////////////////////////////////
    	  ReflectionExecutor.execute(gaInfo, individual);
    	  tracker.calculateFitness(individual,gaInfo.getClazzBranches(clzToTest));
		  totalCoveredBranches =tracker.getTotalCoveredBranch(branchs);

          elapsed = (Calendar.getInstance().getTimeInMillis() - startTime);
          if((iteration%1000)==0 && iteration!=0 ){
              System.out.print("elapsed time: "+ elapsed + " of "+TestTimeout);
              System.out.println("\t Total Branch Covered= ( "+ totalCoveredBranches   +" ) and took "+ iteration +" iterations");
          }
 			if((elapsed/60000)==noMinutes){
  				 if (GAConfig.SaveData) Log.log("At " +  noMinutes +" minute(s) Total Branch Covered= " + totalCoveredBranches );
  				 noMinutes++;
  				System.out.println("At " +  noMinutes +" minute(s) Total Branch Covered= " + totalCoveredBranches );
			}

 			if(totalCoveredBranches>=maximumBranchNumber)
				break;

		}
		return iteration;
	}
	public static void start(TestClusterBuilder tCluster) throws ClassNotFoundException,IOException{
		//Create TestCluster
		initialize( tCluster);
		System.out.println("------------------");
		int iteration=execute();
		String clzToTest=gaInfo.getClzToTest().getName();
		List<Integer> branchs = new ArrayList<Integer>( gaInfo.getClazzBranches(clzToTest));  

		System.out.println("Maximum test time exceeded at "+ elapsed + " ms and took " + iteration + " iterations");
		System.out.println(tracker.displayCoveredBranchs(branchs));
		if (GAConfig.SaveData){ 
			Log.log("Maximum test time exceeded at "+ elapsed + " ms and took " + iteration + " iterations");
			Log.log(tracker.displayCoveredBranchs(branchs));

		}
		tracker.summarizeCoverage(branchs);
		gaInfo.setTracker(tracker);


	}
		
	public static  void setTestTimeout(int i){
	if(i!=0)
	 TestTimeout = 60 * 1000*i;
	else
		 TestTimeout = 60 * 500;
}
	public static void writeLogFile(String cut,int i ){
		String logFilePath = null;
		String fileName = new SimpleDateFormat("MM_dd_yyyy_hhmm'.txt'")
			.format(new Date());
		
	String cName = GAConfig.classFilePath.substring(0,GAConfig.classFilePath.lastIndexOf("/") );
	cName = cName.substring(cName.lastIndexOf("/") +1);
	//cName=GAConfig.classFilePath;

	logFilePath = "./logFiles/"+ cut+ "_RANDOM_"+i+  "_"+ fileName;

		
	if (logFilePath != null) {
		Log.logConfig(logFilePath);
		System.out.println("Log file place: "+ new File(logFilePath).getAbsolutePath());
	}
		Log.log("       SUT               : "+ GAConfig.classFilePath);
		Log.log ("      TestCase Size     : "+GAConfig.TestCaseRandomSize);
		Log.log ("      Timeout           : "+TestTimeout/60000 + " minutes  " + TestTimeout+" ms");
		Log.log ("");

	}
	private static void experiment_configure_options(long TestTimeout,int j) {
		System.out.println("Start testing #..."+j);
		Log.log("Start testing #..."+j);
		Log.log ("      Seed              : "+randomseed);
			  
	}

public static void main(String [] args) throws IOException, ClassNotFoundException{
//Collect all the branches
	ReadFilewgzMDR readFileWGZ = new ReadFilewgzMDR();
	
	 Set<Class<?>> allClasses = new LinkedHashSet<Class<?>>();
     //get class from file
     allClasses.addAll(TestClusterBuilder.readClassFromFile());

     System.out.println("There are " + allClasses.size() + " classes as input");
     
     System.out.println(allClasses);
	List<TestClusterBuilder> TestClusterList= TestClusterBuilder.buildTestClusterList(allClasses);
	 Map<String, BlockClass> blockClasses=readFileWGZ.readFileWGZ(TestClusterList);
	 Map<String,Set<Integer>> classBranches=readFileWGZ.getClazzCondition(blockClasses);
	for (int minutes = 5; minutes <= 5; minutes++) {
		
		for(int times=1 ; times<=1;times++){
			
		for(TestClusterBuilder tCluster:TestClusterList){

		      Map<String,Class<?>> classesToTest = tCluster.getClassToTest();
		      CUT cut=tCluster.getCut();
		      String clz=classesToTest.keySet().iterator().next();
		      System.out.println("Class " + clz + " is being Tested");
		     // System.out.println(classesToTest.keySet().toString());

					if (cut.getMethods().length == 0) {
						System.out.println("\tThere are no methods to test!");
						if (GAConfig.SaveData){
							writeLogFile(clz,minutes);
							Log.log("\tThere are no methods to test!\n");
							Log.log.close();
						}

						continue;
					}
					if (GAConfig.SaveData)
						writeLogFile(clz,minutes);
					if (GAConfig.SaveData)
							Log.log("Class " + clz + " is being Tested");
					
					for (int j = 1; j <= 2; j += 1) {
							try {
								System.out.println("RT Starts testing #..."+ j+ " CUT is "+ clz);
								gaInfo = new GAInfo();
								gaInfo.setClzToTest(cut.getClazz());
								gaInfo.setMapBlockClasses(blockClasses);
								gaInfo.setClazzBranches(classBranches);
								tracker = TrackerCoverage.getTracker();
								randomseed = System.currentTimeMillis();//10;//
								Randomness.reset(randomseed);
								if (GAConfig.SaveData)
										experiment_configure_options(TestTimeout, j);
									
									// RT algorithm = new RT();
								setTestTimeout(minutes);
				
								start(tCluster);
									//				
									/* convert tests to jUnit */
								JUnitTestGenerator gen = new JUnitTestGenerator(GAConfig.getDirGeneratedTests(),gaInfo,"RT",j);
								gen.writeSuite();
								tracker.setTrackerToNull();	

						      
							} catch (Exception e) {
								logger.log(Level.SEVERE, "Something went wrong: "
										+ e.getMessage(), e);
							}
					}
					if (GAConfig.SaveData)
						Log.log.close();

		      }
		}
		}
	

	System.exit(0);
}

}
